RTSP 服务器实现
RTSP 服务器实现
Edmend ZhangRTSP 服务器实现
RTSP协议解析及实现
RTSP是一个实时传输流协议,是一个应用层的协议。通常说的RTSP 包括RTSP协议、RTP协议、RTCP协议,对于这些协议的作用简单的理解如下
- RTSP协议:负责服务器与客户端之间的请求与响应
- RTP协议: 负责服务器与客户端之间传输媒体数据
- RTCP协议:负责提供有关RTP传输质量的反馈,就是确保RTP传输的质量
三者的关系: rtsp并不会发送媒体数据,只是完成服务器和客户端之间的信令交互,rtp协议负责媒体数据传输,rtcp负责rtp数据包的监视和反馈。rtp和rtcp并没有规定传输层的类型,可以选择udp和tcp。Rtsp的传输层则要求是基于tcp。
通过一个ffmpeg 客户端拉流播放一个rtsp视频流的方式,展示RTSP的交互过程。并通过Wireshark抓包分析。
1 | SDP 协议(https://blog.csdn.net/uianster/article/details/125902301) |
- main
1 | // 创建socket描述符 |
Wireshark 捕获
本地客户端访问本地服务 通过网络回环地址 127.0.0.1 所以选择 Adapter for loopback traffic capture
筛选所捕获的rtsp数据如下所示
1 | OPTIONS: 获取服务器支持的方法 |
客户端发起 OPITION 返回RTSP -> 又发起DESCRIBE -> 返回RTSP/SDP数据
发起SETUP请求 端口后加入 track0 这是为了区别建立流的通道
RTSP transport 规范不同 RTP/AVP/UDP
- doclient
1 | while (true) { |
ffmpeg
ffmpeg 三大命令行工具
- ffmpeg 主要是多媒体的编解码工具 ,具体功能主要包括视频裁剪、去水印 、添加logo、提取封面、提取音视频等。
- ffplay 提供了音视频显示和播放相关的图像信息,音频的波形信息等,是个播放器。
- ffprobe 是多媒体分析工具 比如音视频的参数、媒体容器的参数信息等。可以分析媒体文件每个包的长度、包的类型、帧的信息等。
ffmpeg 命令行
视频生成图片
1 | ffmpeg -i input.mp4 -r 25 -g image2.data/image%3d.jpg |
图片合成视频
1 | ffmpeg -r 1 -f image2 -i data/%d.jpg -vcodec libx264 -s 640*480 g 1 -keyint_min 1 -sc_threshold 0 -pix_fmt yuv420p out.mp4 |
概念补充
GOP:GOP(Group of Pictures)是指一组图像序列,它定义了视频编码的结构和压缩效率。GOP长度则表示在该组图像序列中包含的帧数。GOP的结构通常包括以下几种类型的帧:
- I帧(Intra-coded frame):完全独立编码,不依赖其他帧,可以作为随机访问点(例如视频的起始点)。
- P帧(Predictive-coded frame):使用之前的I帧或P帧作为参考来进行预测编码,压缩效率较高。
- B帧(Bi-directional predictive-coded frame):使用前后帧(I帧或P帧)作为参考进行预测编码,压缩效率最高,但解码复杂度也最大。
GOP长度决定了视频流中I帧的频率。例如,一个GOP长度为12的视频流表示每12帧就会有一个I帧,其余的帧可能是P帧或B帧。较短的GOP长度(例如GOP长度为1)意味着更多的I帧,从而提高视频的随机访问性能,但会增加数据量。较长的GOP长度则会减少I帧数量,提高压缩效率,但会降低随机访问性能。
摄像头推拉流&桌面推拉流
1 | 查看摄像头列表 |
摄像头推流到RTMP服务
1 | ffmpeg -f dshow -i video="USB webcam" -vcodec libx264 -acodec aac -ar 44100 -ac 1 -r 25 -s 1920*1080 -f flv rtmp://192.168.1.3/live/desktop |
摄像头推流到RTSP (rtp over tcp)
1 | ffmpeg -f dshow -i video="FULL HD webcam" -rtsp transport tcp -vcodec libx264 -preset -ultrafast -acodec libmp3lame -ar 44100 -ac 1 -r 25 -s 1920*1080 -f rtsp rtsp://192.168.1.3/live/desktop |
windows桌面推流 RTSP&RTMP
1 | ffmpeg -f gdigrab -i desktop -vcodec libx264 ultrafash 0acodec libmp3lame -ar 44100 -ac 1 -r 25 -s 1920*1080 -f flv rtmp://192.168.1.3/live/desktop |
windows桌面推流到RTSP服务
ffmpeg基本推拉流命令
1 | RTMP推流 -re表示复制本地文件 -a表示对音频进行操作 -an表示对音频进行禁用 |
ffmpeg 基本操作
指定时间段录制 -c:v copy 视频文件和源文件保持一致 -c:a copy 音频文件和源文件保持一致
1 | ffmpeg -i input.mp4 -c:v copy -c:a copy ss 00:30:20 out.mp4 |
提取h264 裸码流
1 | ffmpeg -i input.mp4 -c:v copy -bsf:v h264_mp4toannexb -an out.h264 |
实现传输h264的RTSP服务器
概念补充
CSRC 计数器
CSRC(Contributing Source)计数器通常用于实时传输协议(RTP, Real-time Transport Protocol)中,特别是在涉及多路音频或视频流的情况下。RTP是一种用于在网络上传输实时数据的协议,广泛应用于视频会议、IP电话、流媒体等实时通信应用中。
CSRC 计数器的概念
- CSRC 标识符(CSRC Identifier):在 RTP 包头中,有一个字段叫做 CSRC 列表(CSRC list),用于列出所有为当前 RTP 包贡献数据的源。每个源都有一个唯一的标识符,称为 CSRC 标识符。
- CSRC 计数器:RTP 包头中有一个字段用于存储 CSRC 标识符的数量,即 CSRC 计数器。它指示了当前 RTP 包中有多少个源贡献了数据。
CSRC 计数器的作用
CSRC 计数器的主要作用是帮助接收端了解当前 RTP 包是由哪些源生成或混合而成的。这在混合器(mixer)或中继器(translator)等场景中尤为重要,这些设备会接收多个源的流,并将它们组合成一个新的 RTP 流发送给接收端
1 | RTP头的结构体 |
- RTP 包的结构体
1 | RTP包的结构体 |
H264
https://blog.csdn.net/xt18971492243/article/details/123360569
一、H264压缩技术主要采用了以下几种方法对视频数据进行压缩:
帧内预测压缩,解决的是空域数据冗余问题。
帧间预测压缩(运动估计与补偿),解决的是时域数据冗徐问题。
整数离散余弦变换(DCT),将空间上的相关性变为频域上无关的数据然后进行量化。
CABAC压缩。
经过压缩后的帧分为:I帧,P帧和B帧:
I帧:关键帧,采用帧内压缩技术。
P帧:向前参考帧,在压缩时,只参考前面已经处理的帧。采用帧音压缩技术。
B帧:双向参考帧,在压缩时,它即参考前而的帧,又参考它后面的帧。采用帧间压缩技术。
除了I/P/B帧外,还有图像序列GOP。
二、h264组成
1、网络提取层 (Network Abstraction Layer,NAL)
每一张图片压缩出来的结果都是一个独立的NAL
NALU(Network Abstraction Layer Unit,网络抽象层单元)是视频编码中非常重要的概念,特别是在H.264/AVC和H.265/HEVC等现代视频编码标准中。NALU用于组织和传输编码视频数据,使其适应不同的传输网络和存储介质。一个NALU由两个主要部分组成:NAL头(NAL Header)和NAL有效载荷(NAL Payload)。
NAL头(NAL Header):
- 包含关于NALU类型、优先级等信息。
- 在H.264中,NAL头通常是1个字节,包含以下几个字段:
- forbidden_zero_bit(1位):这个位必须为0,如果不为0,说明存在错误。
- nal_ref_idc(2位):指示该NALU的优先级,0表示最低优先级,3表示最高优先级。
- nal_unit_type(5位):指示NALU的类型,如I帧、P帧、SPS、PPS等。
- 在H.265中,NAL头更加复杂,包含2个字节,提供更多的描述信息。
NAL有效载荷(NAL Payload):
- 包含实际的视频编码数据,例如编码的帧数据(如I帧、P帧、B帧),SEI消息(Supplemental Enhancement Information,补充增强信息),SPS(Sequence Parameter Set,序列参数集),PPS(Picture Parameter Set,图像参数集)等。
2、视讯编码层 (Video Coding Layer,VCL)
对于形成网络提取层过程的描述
三、码流结构
H.264的功能分为两层,视频编码层(VCL)和网络提取层(NAL)。
1.VCL数据即被压缩编码后的视频数据序列。
2.在VCL数据要封装到NAL单元中之后,才可以用来传输或存储
SPS:序列参数集,作用于一系列连续的编码图像;
PPS:图像参数集,作用于编码视频序列中一个或多个独立的图像;
用来存储分辨率等一系列信息
四、IDR帧
是一种特殊的I帧,常用于视频编码和压缩技术中,特别是在H.264/AVC和H.265/HEVC等视频编码标准中。
IDR帧的特点
- 独立解码:IDR帧可以独立解码,不依赖于之前的任何帧。这意味着解码器在解码IDR帧时不需要参考之前的帧,从而提供一个新的解码起点。
- 清除参考帧列表:当解码器遇到一个IDR帧时,它会清除之前所有的参考帧。这防止了解码器使用过时的参考帧进行错误预测,从而保证解码的一致性和准确性。
- 随机访问点:IDR帧通常被用作视频流中的随机访问点(Random Access Point),允许从该帧开始进行无缝播放或快进/快退等操作。
IDR帧在视频编码中的作用
- 视频切片:IDR帧允许视频流被分割成独立的片段,每个片段可以独立解码和播放。这对于视频编辑和处理非常重要。
- 错误恢复:在有损网络环境中(例如流媒体传输),视频数据可能会丢失或损坏。IDR帧提供了一个清晰的恢复点,从而提高了视频流的鲁棒性和稳定性。
- 直播和点播:在直播或点播视频流中,IDR帧允许观众在任意时间点加入直播,而无需从视频的开头开始观看。
IDR帧与I帧的区别
普通I帧:完全独立,可以解码自身,不依赖任何其他帧。它可以被后续的帧引用作为参考。
IDR帧:不仅是独立解码的I帧,而且会强制清除解码器的参考帧缓存,确保后续帧不再引用IDR帧之前的帧。它用于实现视频流的切断点或关键帧,使得在流媒体中可以从该帧开始进行无缝播放或跳转。
H264 码流进行RTP封装
H.264由一个一个的NALU组成,每个NALU之间使用00 00 00 01
或00 00 01
分隔开,每个NALU的第一次字节都有特殊的含义
NALU(Network Abstraction Layer Unit)NALU是视频流的基本单位,每个NALU包含一段编码后的视频数据。视频编码器将原始视频帧编码为NALU,然后将这些NALU打包成RTP(实时传输协议)包进行传输。
1 | 常用Nalu_type: |
注:SPS和PPS只是编码解码的参数 不是视频数据
SPS 和 PPS 定义的是视频流的结构和参数,这些信息在一个视频序列中相对稳定,不需要在每个帧上进行时间同步。它们不代表具体的帧数据,而是描述解码器如何解释后续的实际帧数据。
从一个H.264的文件中将一个一个的NALU提取出来,然后封装成RTP包
1,F(forbiden):禁止位,占用NAL头的第一个位,当禁止位值为1时表示语法错误;
2,NRI:参考级别,占用NAL头的第二到第三个位;值越大,该NAL越重要。(重要级别)
3,Type:Nal单元数据类型,也就是标识该NAL单元的数据类型是哪种,占用NAL头的第四到第8个位;
- H.264可以由三种RTP打包方式
(1)单NALU打包: 一个RTP包包含一个完整的NALU。将一整个NALU的数据放入RTP包的载荷中,这是最简单的一种方式。
(2)聚合打包:对于较小的NALU,一个RTP包可包含多个完整的NALU
(3)分片打包:对于较大的NALU,一个NALU可以分为多个RTP包发送 每个RTP包都有大小限制的,因为RTP一般都是使用UDP发送,UDP没有流量控制,所以要限制每一次发送的大小,所以如果一个NALU的太大,就需要分成多个RTP包发送,至于如何分成多个RTP包
当我们进入play method的时候,需要都H264文件,进行封包,RTCP/UDP 通道 传输
视频数据封装和传输:
- 视频编码:NALU是视频流的基本单位,每个NALU包含一段编码后的视频数据。视频编码器将原始视频帧编码为NALU,然后将这些NALU打包成RTP(实时传输协议)包进行传输。
- 传输效率:通过将视频数据划分为多个NALU,可以提高传输效率和适应不同网络条件。例如,在不可靠的网络条件下,丢失一个NALU不会影响整个视频流的解码。
解码和播放:
- NALU解析:RTSP客户端接收RTP包后,需要解析NALU以重建原始的视频帧。解析NALU是解码过程的关键步骤,它决定了视频流的质量和流畅性。
- 同步播放:NALU中包含时间戳信息,用于在客户端同步播放视频和音频流。正确解析这些时间戳对于实现流畅的播放体验至关重要。
错误恢复和重传:
- 错误检测:NALU的头部信息可以帮助检测传输中的错误,并根据需要进行错误恢复。RTSP服务器和客户端可以使用这些信息来判断NALU是否丢失或损坏。
- 重传机制:如果检测到NALU丢失或损坏,RTSP服务器可以根据需要启动重传机制,以确保视频流的完整性和质量。
SSRC
SSRC(Synchronization Source identifier)是实时传输协议(RTP)中的一个重要概念。它用于标识参与 RTP 会话的各个数据源,以实现同步和管理。每个 RTP 数据包都包含一个 SSRC 标识符,用于标识数据包的源。这个标识符是随机生成的,目的是确保在同一 RTP 会话中,每个数据源都有一个唯一的标识符。
同步和多路复用:
- 在 RTP 会话中,同步多个数据流(如音频和视频)是至关重要的。SSRC 使接收端能够正确地同步这些流,确保音频和视频之间的协调一致。
- 多路复用是指在同一 RTP 会话中传输多个数据流。通过使用不同的 SSRC 标识符,可以在同一会话中传输和管理多个数据流,而不会发生混淆。
冲突检测和解决:
- 在 RTP 会话中,如果两个不同的数据源生成了相同的 SSRC 标识符,就会发生冲突。RTP 规范提供了冲突检测和解决机制。例如,当检测到 SSRC 冲突时,数据源会生成一个新的 SSRC 标识符并继续发送数据。
- 冲突检测机制确保了 SSRC 标识符的唯一性,从而保证了数据流的正确标识和管理。
生成:
- 当一个 RTP 会话开始时,每个数据源会随机生成一个 32 位的 SSRC 标识符。这个标识符在会话期间应保持不变,以确保数据流的一致性。
传输:
- 在每个 RTP 数据包的头部,都包含一个 SSRC 字段,用于标识该数据包的源。接收端使用这个 SSRC 标识符来区分和管理不同的数据流。
- 例如,在视频会议中,音频和视频数据包会分别带有不同的 SSRC 标识符,接收端根据 SSRC 将音频和视频流进行同步和播放。
RTP包的格式是绝不会变的,永远是RTP头+RTP载荷
如何解决无法区分RTP 是分片打包的头尾还是中间
第一个字节位**FU Indicator**
,其格式如下
高三位:与NALU第一个字节的高三位相同
Type:28,表示该RTP包一个分片,为什么是28
第二个字节位**FU Header**
,其格式如下
S:标记该分片打包的第一个RTP包
E:比较该分片打包的最后一个RTP包
Type:NALU的Type
1 | //开始播放,发送RTP包 |
根据3 or 4个分隔符每次读取一个NALU
1 | static int getFrameFromH264File(FILE* fp, char* frame, int size) { |
将 H.264 视频帧分片和封装到 RTP 包中的功能,并通过 UDP 发送
1 | static int rtpSendH264Frame(int serverRtpSockfd, const char* ip, int16_t port, |